package robotmanager

import (
	"context"
	"errors"
	"fmt"
	"sort"
	"sync"

	"dev.ixmxm.top/rms/boot"
	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/utils/function"
	"dev.ixmxm.top/rms/utils/log"
	"dev.ixmxm.top/rms/utils/tools"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var robotM RobotManager

type RobotManager struct {
	robots            *sync.Map
	robotGroups       *sync.Map
	db                *boot.MongoDB
	timerChargerList  []model.DayChargerRule
	timerChargerLock  sync.Mutex
	reconnectCallback func(robot *model.Robot)
}

func init() {
	ctx := tools.NewContext()
	robotM = RobotManager{}
	robotM.robots = &sync.Map{}
	robotM.robotGroups = &sync.Map{}
	robotM.db = boot.GetMongoClient()
	err := loadAllRobotToCache(ctx)
	if err != nil {
		log.Panicf("load robot data error")
		return
	}

	err = ReloadRobotGroup(ctx)
	if err != nil {
		log.Panicf("load robot group error")
		return
	}

	robotM.timerChargerList = make([]model.DayChargerRule, 0)
	err = LoadTimerChargerRules(ctx)
	if err != nil {
		log.Panicf("load robot timer charger error")
		return
	}
}

func SetReconnectCallBack(reconnectCallback func(robot *model.Robot)) {
	robotM.reconnectCallback = reconnectCallback
}

func GetFromCache(agvID string) *model.Robot {
	data, _ := robotM.robots.Load(agvID)
	if data == nil {
		return nil
	}
	return data.(*model.Robot)
}

func GetAllFromCache() map[string]*model.Robot {
	robotMap := make(map[string]*model.Robot)
	robotM.robots.Range(func(key, value interface{}) bool {
		robotMap[key.(string)] = value.(*model.Robot)
		return true
	})
	return robotMap
}

//SetEnableToDB 修改机器人使能
func SetEnableToDB(ctx context.Context, agvID string, enable bool) codes.Code {
	_, err := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).UpdateOne(ctx, bson.M{"agv_id": agvID}, bson.M{"$set": bson.M{"is_enable": enable}})
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return codes.ErrRobotNotExists
		}
		log.ErrorfWithContext(ctx, "update robot enable to db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	robot := GetFromCache(agvID)

	robot.Account.IsEnable = enable
	if !enable {
		robot.Status = nil
		robot.AgvCorverNodes = make([]string, 0)
		robot.AgvCorverPaths = make([]string, 0)
	}
	return nil
}
func GetLocalSitesFromDB(ctx context.Context, sn string) []string {
	ids := make([]string, 0)
	dbRes := robotM.db.Collection(ctx, model.LocalPath{}.TableName()).FindOne(ctx, bson.M{"sn": sn})
	if dbRes.Err() != nil {
		return ids
	}
	res := new(model.LocalPath)
	if err := dbRes.Decode(res); err != nil {
		return ids
	}
	ids = res.SpecialLocks.ToIds()
	ids = append(ids, res.Paths.AllBlocks().ToIds()...)
	return ids
}

//SetEnableToDB 修改机器人有货无货状态
func SetGoodsStatusToDB(ctx context.Context, task *model.Task, goodsStatus int32) codes.Code {
	agvID := task.AgvId
	robot := GetFromCache(agvID)
	if !robot.StatusIsExists() {
		return nil
	}
	// goods_status, err := strconv.ParseInt(goodsStatus, 10, 32)
	// if err != nil {
	// 	return codes.ErrRobotNotExists
	// }
	// goods_status_1 := int32(goods_status)
	//判断任务
	// if task.Type == model.TaskTypePick {
	// 	//取货判断

	// } else if task.Type == model.TaskTypePut {

	// }
	if goodsStatus == 1 || goodsStatus == 2 {
		goodsStatus = 1
	} else {
		goodsStatus = 0
	}
	_, err := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).UpdateOne(ctx, bson.M{"agv_id": agvID}, bson.M{"$set": bson.M{"goods_status": goodsStatus}})
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return codes.ErrRobotNotExists
		}
		log.ErrorfWithContext(ctx, "update robot enable to db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}

	robot.Account.GoodsStatus = goodsStatus
	return nil
}

//SetFactoryAndFloorToDB 修改机器人启动的地图名
func SetMapNameToDB(ctx context.Context, agvID string, mapName string) codes.Code {
	robot := GetFromCache(agvID)
	if robot == nil {
		return nil
	}
	_, err := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).UpdateOne(ctx, bson.M{"agv_id": agvID}, bson.M{"$set": bson.M{"map_name": mapName}})
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return codes.ErrRobotNotExists
		}
		log.ErrorfWithContext(ctx, "update robot enable to db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}

	robot.Account.MapName = mapName
	return nil
}

//AddAccountToDB 添加机器人入数据库，并增加缓存
func AddAccountToDB(ctx context.Context, robotAccount *model.RobotAccount) codes.Code {
	_, errGetType := GetTypeFromDB(ctx, robotAccount.CategoryID)
	if errGetType != nil {
		return errGetType
	}
	dbRes := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).FindOneAndReplace(ctx, bson.M{"agv_id": robotAccount.AgvId}, robotAccount, &options.FindOneAndReplaceOptions{Upsert: function.BoolPtr(true)})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "add robot type to db error:%s", dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}

	addRobotToCache(ctx, robotAccount)
	return nil
}

//DeleteRobotAccountFromDB 从数据库删除机器人账号，并清除缓存
func DeleteRobotAccountFromDB(ctx context.Context, agvID string) codes.Code {
	_, err := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).DeleteOne(ctx, bson.M{"agv_id": agvID})
	if err != nil {
		log.ErrorfWithContext(ctx, "delete robot account from db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}

	robotM.robots.Delete(agvID)
	return nil
}

//GetAllAccountFromDB 从数据库获得所有机器人信息
func GetAllAccountFromDB(ctx context.Context) ([]*model.RobotAccount, codes.Code) {
	dbRes, err := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).Find(ctx, bson.D{})
	if err != nil {
		if err == mongo.ErrNoDocuments || err == mongo.ErrEmptySlice {
			return nil, nil
		}
		log.ErrorfWithContext(ctx, "get all robot accounts from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	robotsAccount := make([]*model.RobotAccount, 0)
	if errBind := dbRes.All(ctx, &robotsAccount); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all robot accounts from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return robotsAccount, nil
}

//GetAccountFromDBByGroup 从数据库获得分组下的机器人
func GetAccountFromDBByGroup(ctx context.Context, groupId string) ([]*model.RobotAccount, codes.Code) {

	var condition interface{}
	if groupId != "" {
		condition = bson.M{"group_id": groupId}
	} else {
		condition = bson.M{"$or": []bson.M{
			bson.M{"group_id": ""},
			bson.M{"group_id": nil},
			bson.M{"group_id": bson.M{"$exists": false}},
		},
		}
	}

	dbRes, err := robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).Find(ctx, condition)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all robot accounts from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	robotsAccount := make([]*model.RobotAccount, 0)
	if errBind := dbRes.All(ctx, &robotsAccount); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all robot accounts from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return robotsAccount, nil
}

//AddType 添加机器人类型到数据库，并增加缓存
func AddType(ctx context.Context, robotType *model.RobotType) codes.Code {
	//写入数据库
	dbRes := robotM.db.Collection(ctx, model.RobotType{}.TableName()).FindOneAndReplace(ctx, bson.M{"category_id": robotType.CategoryId}, robotType, &options.FindOneAndReplaceOptions{Upsert: function.BoolPtr(true)})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "add robot type to db error:%s", dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}

	//更新缓存
	for _, r := range GetAllFromCache() {
		if r.Type.CategoryId == robotType.CategoryId {
			r.Type = *robotType
		}
	}
	return nil
}

//AddTypeToDB 添加机器人类型到数据库，并增加缓存
func AddTypeToDB(ctx context.Context, robotType *model.RobotType) codes.Code {
	//写入数据库
	dbRes := robotM.db.Collection(ctx, model.RobotType{}.TableName()).FindOneAndReplace(ctx, bson.M{"category_id": robotType.CategoryId}, robotType, &options.FindOneAndReplaceOptions{Upsert: function.BoolPtr(true)})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "add robot type to db error:%s", dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}

	//更新缓存
	for _, r := range GetAllFromCache() {
		if r.Type.CategoryId == robotType.CategoryId {
			r.Type = *robotType
		}
	}
	return nil
}

//DeleteTypeFromDB 从数据库删除指定机器人类型
func DeleteTypeFromDB(ctx context.Context, categoryID int) codes.Code {
	for _, robot := range GetAllFromCache() {
		if robot.Type.CategoryId == categoryID {
			return codes.ErrRobotTypeExists
		}
	}
	_, err := robotM.db.Collection(ctx, model.RobotType{}.TableName()).DeleteOne(ctx, bson.M{"category_id": categoryID})
	if err != nil {
		log.ErrorfWithContext(ctx, "delete robot types from db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	return nil
}

//GetTypeFromDB 从数据库获得机器人类型
func GetTypeFromDB(ctx context.Context, categoryID int) (*model.RobotType, codes.Code) {
	dbRes := robotM.db.Collection(ctx, model.RobotType{}.TableName()).FindOne(ctx, bson.M{"category_id": categoryID})
	if dbRes.Err() != nil {
		log.ErrorfWithContext(ctx, "get robot type:%d from db error:%s", categoryID, dbRes.Err().Error())
		return nil, codes.ErrDatabase.Wrap(dbRes.Err())
	}
	robotType := new(model.RobotType)
	if errBind := dbRes.Decode(robotType); errBind != nil {
		log.ErrorfWithContext(ctx, "bind robot type from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return robotType, nil
}

//GetAllTypesFromDB 从数据库获得所有机器人类型
func GetAllTypesFromDB(ctx context.Context) ([]*model.RobotType, codes.Code) {
	dbRes, err := robotM.db.Collection(ctx, model.RobotType{}.TableName()).Find(ctx, bson.D{})
	if err != nil {
		log.ErrorfWithContext(ctx, "get all robot types from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	robotTypes := make([]*model.RobotType, 0)
	if errBind := dbRes.All(ctx, &robotTypes); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all robot types from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return robotTypes, nil
}

//AddGroupToDB 添加机器人分组到数据库
func addGroupToDB(ctx context.Context, robotGroup *model.RobotGroup) codes.Code {
	//写入数据库
	robotGroup.Id = primitive.NewObjectID()
	_, errInsert := robotM.db.Collection(ctx, robotGroup.TableName()).InsertOne(ctx, robotGroup)
	if errInsert != nil {
		log.ErrorfWithContext(ctx, "insert task to db error:%s", errInsert.Error())
		return codes.ErrDatabase.Wrap(errInsert)
	}
	return nil
}

//DeleteGroupFromDB 从数据库删除指定机器人分组
func deleteGroupFromDB(ctx context.Context, id primitive.ObjectID) codes.Code {
	_, err := robotM.db.Collection(ctx, model.RobotGroup{}.TableName()).DeleteOne(ctx, bson.M{"_id": id})
	if err != nil {
		log.ErrorfWithContext(ctx, "delete robot group from db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)

	}
	_, err = robotM.db.Collection(ctx, model.RobotAccount{}.TableName()).UpdateMany(ctx, bson.M{"group_id": id.Hex()}, bson.M{"$set": bson.M{"group_id": ""}})

	if err != nil {
		log.ErrorfWithContext(ctx, "delete robot group from db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	return nil
}

//DeleteGroupFromDB 从数据库删除指定机器人分组
func updateGroupFromDB(ctx context.Context, group *model.RobotGroup) (int64, codes.Code) {
	res, err := robotM.db.Collection(ctx, model.RobotGroup{}.TableName()).UpdateOne(ctx, bson.M{"_id": group.Id},
		bson.M{"$set": bson.M{"name": group.Name, "map_list": group.MapList, "update_time": group.UpdateTime}})
	if err != nil {
		log.ErrorfWithContext(ctx, "update robot group from db error:%s", err.Error())
		return 0, codes.ErrDatabase.Wrap(err)
	}
	return res.ModifiedCount, nil
}

//GetGroupFromDB 从数据库获得机器人分组
func getGroupFromDB(ctx context.Context, groupID primitive.ObjectID) (*model.RobotGroup, codes.Code) {
	dbRes := robotM.db.Collection(ctx, model.RobotGroup{}.TableName()).FindOne(ctx, bson.M{"_id": groupID})
	if dbRes.Err() != nil {
		log.ErrorfWithContext(ctx, "get robot group:%d from db error:%s", groupID, dbRes.Err().Error())
		return nil, codes.ErrDatabase.Wrap(dbRes.Err())
	}
	robotGroup := new(model.RobotGroup)
	if errBind := dbRes.Decode(robotGroup); errBind != nil {
		log.ErrorfWithContext(ctx, "bind robot group from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return robotGroup, nil
}

//GetAllGroupsFromDB 从数据库获得所有机器人分组
func getAllGroupsFromDB(ctx context.Context) ([]*model.RobotGroup, codes.Code) {
	dbRes, err := robotM.db.Collection(ctx, model.RobotGroup{}.TableName()).Find(ctx, bson.D{})
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, nil
		}
		log.ErrorfWithContext(ctx, "get all robot groups from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	robotGroups := make([]*model.RobotGroup, 0)
	if errBind := dbRes.All(ctx, &robotGroups); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all robot groups from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return robotGroups, nil
}

//导入所有的AGV类型数据
func ImportAllRobtType(ctx context.Context, robotTypes []interface{}) codes.Code {
	log.Infof("开始清空(AGV信息、AGV类型)，并且将excel所有机器人类型数据导入")
	ctxTx := boot.Begin(ctx)

	//1.先删除所有的机器人配置数据
	_, err := robotM.db.Collection(ctxTx, model.RobotAccount{}.TableName()).DeleteMany(ctxTx, bson.D{})
	if err != nil {
		ctxTx.Rollback()
		log.ErrorfWithContext(ctx, "clear all agvInfo from db. error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	//2.删除所有的AGV类型
	_, err1 := robotM.db.Collection(ctxTx, model.RobotType{}.TableName()).DeleteMany(ctxTx, bson.D{})
	if err1 != nil {
		ctxTx.Rollback()
		log.ErrorfWithContext(ctx, "clear all robottype from db. error:%s", err1.Error())
		return codes.ErrDatabase.Wrap(err1)
	}
	//3.插入所有的AGV类型
	_, err2 := robotM.db.Collection(ctxTx, model.RobotType{}.TableName()).InsertMany(ctxTx, robotTypes)
	if err2 != nil {
		ctxTx.Rollback()
		log.ErrorfWithContext(ctx, "insert many robottypes to db. error:%s", err2.Error())
		return codes.ErrDatabase.Wrap(err2)
	}
	ctxTx.Commit()
	return nil
}

//GetAllRobotsInSameMapFromCache 从缓存获得所有使用同地图的robot
func GetAllRobotsInSameMapFromCache(mapName string) []*model.Robot {
	res := make([]*model.Robot, 0)
	for _, r := range GetAllFromCache() {
		if r.Status != nil {
			// r.Update(r.Account.AgvIP, r.Account.AgvPort, robotM.reconnectCallback)
		}
		if r.Account.MapName == mapName {
			res = append(res, r)
		}
	}
	return res
}

//GetAllRobotsFromCache 从缓存获得所有robot
func GetAllRobotsFromCache() []*model.Robot {
	res := make([]*model.Robot, 0)
	for _, r := range GetAllFromCache() {
		if r.Status != nil {
			// r.Update(r.Account.AgvIP, r.Account.AgvPort, robotM.reconnectCallback)
		}
		res = append(res, r)
	}
	return res
}

//获得所有存在状态的列表
func GetAllExitStatusRobotsFromCache() []*model.Robot {
	res := make([]*model.Robot, 0)
	for _, r := range GetAllFromCache() {
		if r.Status != nil {
			// r.Update(r.Account.AgvIP, r.Account.AgvPort, robotM.reconnectCallback)
		}
		if r.StatusIsExists() {
			res = append(res, r)
		}
	}
	return res
}

// 从缓存获得所有空闲robot(空闲、待命中)
func GetAllFreeRobotsFromCache() []*model.Robot {
	res := make([]*model.Robot, 0)
	for _, r := range GetAllRobotsFromCache() {
		if r.Status != nil {
			// r.Update(r.Account.AgvIP, r.Account.AgvPort, robotM.reconnectCallback)
		}
		if !r.RobotIsUse() {
			continue
		}
		if r.Status.Status == model.RobotStatusIdle || r.Status.Status == model.RobotStatusStandby {
			res = append(res, r)
		}
	}
	return res
}

// 从缓存获得所有可下发任务的robot(空闲、待命中、执行待命、充电中)
func GetAllTaskRobotsFromCache() []*model.Robot {
	res := make([]*model.Robot, 0)
	for _, r := range GetAllFromCache() {
		if r.Status != nil {
			// r.Update(r.Account.AgvIP, r.Account.AgvPort, robotM.reconnectCallback)
		}
		if !r.RobotIsUse() {
			continue
		}
		if r.Status.Status == model.RobotStatusIdle || r.Status.Status == model.RobotStatusStandby ||
			r.Status.Status == model.RobotStatusCharging || r.Status.Status == model.RobotStatusExecStandby {
			res = append(res, r)
		} else if r.CanBeCancel {
			res = append(res, r)
		}
	}
	return res
}

func MapUseInRobotsCache(ctx context.Context, mapName string) bool {
	for _, r := range GetAllFromCache() {
		if r.Account.MapName == mapName {
			return true
		}
	}

	groups, code := getAllGroupsFromDB(ctx)
	if code != nil {
		return false
	}
	for _, g := range groups {
		if g.MapList == nil || len(g.MapList) < 1 {
			continue
		}
		if tools.StringSliceIsContain(g.MapList, mapName) {
			return true
		}
	}
	return false
}

type RobotStatusRes []model.RobotStatus

func (x RobotStatusRes) Len() int           { return len(x) }
func (x RobotStatusRes) Less(i, j int) bool { return x[i].AgvId < x[j].AgvId }
func (x RobotStatusRes) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }

//GetAllRobotStatusFromCache 从缓存获得所有机器人状态，按agv id排序
func GetAllRobotStatusFromCache() []model.RobotStatus {
	res := make(RobotStatusRes, 0)
	for _, robot := range GetAllRobotsFromCache() {
		if robot.Status != nil {
			robot.Update(robot.Account.AgvIP, robot.Account.AgvPort, robotM.reconnectCallback)
			res = append(res, robot.GetStatus())
		}
	}
	sort.Sort(res)
	return res
}

//UpdateStatusToCache 刷新缓存中的机器人状态数据
func UpdateStatusToCache(status *model.RobotStatus) {

	r, find := robotM.robots.Load(status.AgvId)
	if !find {
		log.Warnf("get unregistered robot status:%s", status.AgvId)
		return
	}
	robot := r.(*model.Robot)
	status.LastCommTime = model.Now()
	robot.UpdateStatus(status)
}

//UpdateStatusToCache 刷新缓存中的机器人状态数据
func UpdateTaskOnlineStatusToCache(agvId string, taskOnline bool) {
	log.Infof("UpdateTaskOnlineStatusToCache agvId:%s taskOnline:%t", agvId, taskOnline)
	r, find := robotM.robots.Load(agvId)
	if !find {
		log.Warnf("get unregistered robot status:%s", agvId)
		return
	}
	r.(*model.Robot).UpdateTaskOnlineStatus(taskOnline)
}
func UpdateTaskFlgToCache(agvId string, canCancel bool) {

	r, find := robotM.robots.Load(agvId)
	if !find {
		log.Warnf("get unregistered robot status:%s", agvId)
		return
	}
	r.(*model.Robot).UpdateTaskFlg(canCancel)
}

//addRobotToCache 添加robot到缓存，方便状态更新和获得
func addRobotToCache(ctx context.Context, robotAccount *model.RobotAccount) {
	rData, find := robotM.robots.Load(robotAccount.AgvId)
	var status *model.RobotStatus
	taskOnline := false
	if find {
		r := rData.(*model.Robot)
		status = r.Status
		taskOnline = r.TaskOnline
	}
	robotType, errGetType := GetTypeFromDB(ctx, robotAccount.CategoryID)
	if errGetType != nil {
		log.PanicfWithContext(ctx, "load robots to cache error,can not get types:%s", errGetType.UnWrapError())
	}
	robotM.robots.Store(robotAccount.AgvId, &model.Robot{Account: robotAccount, Type: *robotType, Status: status, TaskOnline: taskOnline})
}

// 重新加载机器人分组信息
func ReloadRobotGroup(ctx context.Context) codes.Code {
	robotM.robotGroups = &sync.Map{}
	groups, err := getAllGroupsFromDB(ctx)
	if err != nil {
		return err
	}

	if groups == nil {
		return nil
	}

	for index, _ := range groups {
		robotM.robotGroups.Store(groups[index].Id.Hex(), groups[index])
	}
	return nil
}

// AddRobotGroup 添加分组
func AddRobotGroup(ctx context.Context, g *model.RobotGroup) codes.Code {
	err := addGroupToDB(ctx, g)
	if err != nil {
		return err
	}
	robotM.robotGroups.Store(g.Id.Hex(), g)
	return nil
}

// UpdateRobotGroup 跟新分组
func UpdateRobotGroup(ctx context.Context, g *model.RobotGroup) codes.Code {
	effectRows, err := updateGroupFromDB(ctx, g)
	if err != nil {
		return err
	}
	if effectRows == 0 {
		return codes.ErrRobotGroupNotExists
	}
	robotM.robotGroups.Store(g.Id.Hex(), g)
	return nil
}

// GetRobotGroup 获取一个机器人分组
func GetRobotGroup(id string) (*model.RobotGroup, bool) {
	groupI, isOK := robotM.robotGroups.Load(id)
	if !isOK {
		return nil, false
	}
	return groupI.(*model.RobotGroup), true
}

// GetAllRobotGroup 获取所有机器人分组
func GetAllRobotGroup() []*model.RobotGroup {
	groups := make([]*model.RobotGroup, 0)
	robotM.robotGroups.Range(func(key, value interface{}) bool {
		g := value.(*model.RobotGroup)
		groups = append(groups, g)
		return true
	})
	return groups
}

// DeleteRobotGroup 删除一个机器人分组
func DeleteRobotGroup(ctx context.Context, id string) (bool, codes.Code) {
	pID, err := primitive.ObjectIDFromHex(id)
	if err != nil {
		return false, codes.ErrInvalidParams.Wrap(err)
	}

	txctx := boot.Begin(ctx)
	errCode := deleteGroupFromDB(txctx, pID)
	if err != nil {
		txctx.Rollback()
		return false, errCode
	}

	errCode = loadAllRobotToCache(txctx)
	if err != nil {
		txctx.Rollback()
		return false, errCode
	}
	txctx.Commit()
	robotM.robotGroups.Delete(id)
	return true, nil
}

//loadAllRobotToCache 加载机器人到缓存
func loadAllRobotToCache(ctx context.Context) codes.Code {
	robotsAccount, errGetAllRobots := GetAllAccountFromDB(ctx)
	if errGetAllRobots != nil {
		log.ErrorfWithContext(ctx, "load robots to cache error,can not get robot accounts:%s", errGetAllRobots.UnWrapError())
		return errGetAllRobots
	}

	for _, r := range robotsAccount {
		addRobotToCache(ctx, r)
	}
	return nil
}

//获取系统配置
func GetConfigFromDb(ctx context.Context) (*model.SystemConfig, codes.Code) {
	dbRes := robotM.db.Collection(ctx, model.SystemConfig{}.TableName()).FindOne(ctx, bson.M{"id": 1})
	if dbRes.Err() != nil {
		log.ErrorfWithContext(ctx, "获取系统配置 from db error:%s", dbRes.Err().Error())

		if errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
			log.Warnf("读取数据库配置有误，启动默认配置")
			config := &model.SystemConfig{
				Id: 0,
				LogCfg: model.LogCfg{
					LogLevel:            0,
					LogDbLevel:          1,
					LogMaxAge:           2,
					AutoCleanDbInterval: 2,
				},
				RobotOnlineCfg: model.RobotOnlineCfg{
					LineOffsetLength:  200,
					LineOffsetAngle:   9,
					LineOffsetSiteDis: 15000,
				},
				TrafficCfg: model.TrafficCfg{
					UseReroute: true,
					RerouteCfg: model.RerouteCfg{
						WaitTime:            30,
						CostSwitchTime:      30,
						LowCostSwitchSlope:  0.5,
						HighCostSwitchSlope: 50,
						SiteHotCostSlope:    0.2,
					},
					UseTaskAvoid: false,
					TaskAvoidCfg: model.TaskAvoidCfg{
						UseSiteStatus:        false,
						NoIntoFullSite:       true,
						CheckAvoidSiteNumber: 5,
						NearCalculateNumber:  10,
						AvoidTriggerTime:     20,
						WaitIdleAgvTime:      60,
					},
					UseIdleAvoid: false,
					IdleAvoidCfg: model.IdleAvoidCfg{
						AvoidSearchDistance: 60,
					},
					StandbyTime:       15,
					UseAvoidOtherAgvs: false,
					UsePathMutex:      false,
					PathMutexMapNames: make([]string, 0),
				},
				MiddlewareCfg: model.MiddlewareCfg{
					Ip:            "127.0.0.1",
					PortApi:       8091,
					PortWebsocket: 9091,
				},
			}
			AddConfigToDB(ctx, config)
			return config, nil
		}

		return nil, codes.ErrDatabase.Wrap(dbRes.Err())
	}
	onlineConfig := new(model.SystemConfig)
	if errBind := dbRes.Decode(onlineConfig); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all 获取系统配置 from db error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	if onlineConfig.TrafficCfg.TaskAvoidCfg.WaitIdleAgvTime == 0.0 {
		onlineConfig.TrafficCfg.TaskAvoidCfg.WaitIdleAgvTime = 60.0
	}
	return onlineConfig, nil
}

//AddAccountToDB 添加系统配置到数据库
func AddConfigToDB(ctx context.Context, config *model.SystemConfig) codes.Code {
	config.Id = 1
	dbRes := robotM.db.Collection(ctx, model.SystemConfig{}.TableName()).FindOneAndReplace(ctx, bson.M{"id": 1}, config, &options.FindOneAndReplaceOptions{Upsert: function.BoolPtr(true)})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "添加系统配置到数据库 error:%s", dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}
	return nil
}

func IsAgvHaveTask(ctx context.Context, agvId string) bool {
	dbRes := robotM.db.Collection(ctx, model.MainTask{}.TableName()).FindOne(ctx, bson.M{"agv_id": agvId})
	if dbRes.Err() != nil {
		return false
	}
	record := new(model.MainTask)
	if errBind := dbRes.Decode(record); errBind != nil {
		return false
	}
	if record.TaskId == 0 {
		return false
	}
	return true
}

//---------------------------定时i充电规则---------------------
func LoadTimerChargerRules(ctx context.Context) codes.Code {
	//将所有查询数据放入缓存中
	list, err := GetAllTimerChargerRule(ctx)
	if err != nil {
		return err
	}
	//赋值缓存
	robotM.timerChargerList = list
	return nil
}

//获得所有缓存规则
func GetAllTimerChargerFromCache() []model.DayChargerRule {
	return robotM.timerChargerList
}
func GetOneTimerChargerFromCacheByRuleId(ruleId uint16) (bool, *model.DayChargerRule) {

	for _, value := range robotM.timerChargerList {
		if value.Id == ruleId {
			return true, &value
		}
	}
	return false, nil

}

func UpadteTimerChargerRuleCache(dayChargerRule model.DayChargerRule) {
	find := false
	for i, v := range robotM.timerChargerList {
		if v.Id == dayChargerRule.Id {
			find = true
			robotM.timerChargerList[i] = dayChargerRule
			break
		}
	}
	if !find {
		robotM.timerChargerList = append(robotM.timerChargerList, dayChargerRule)
	}
}

func DeleteRuleById(id uint16) {
	removeElement := func(list []model.DayChargerRule, index int) []model.DayChargerRule {
		return append(list[:index], list[index+1:]...)
	}
	for i, v := range robotM.timerChargerList {
		if v.Id == id {
			list1 := removeElement(robotM.timerChargerList, i)
			robotM.timerChargerList = list1
			break
		}
	}

}

//新增日充电规则
func GetAllTimerChargerRule(ctx context.Context) ([]model.DayChargerRule, codes.Code) {
	rules := make([]model.DayChargerRule, 0)
	res, err := robotM.db.Collection(ctx, model.DayChargerRule{}.TableName()).Find(ctx, bson.M{})
	if err != nil {
		log.ErrorfWithContext(ctx, "get all timer charger rule from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	if errBind := res.All(ctx, &rules); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all timer charger error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return rules, nil
}

//修改日充电规则
func UpdateTimerChargerRule(ctx context.Context, dayChargerRule model.DayChargerRule) codes.Code {
	robotM.timerChargerLock.Lock()
	defer robotM.timerChargerLock.Unlock()
	//更新
	dbRes := robotM.db.Collection(ctx, model.DayChargerRule{}.TableName()).FindOneAndReplace(ctx, bson.M{"id": dayChargerRule.Id}, dayChargerRule, &options.FindOneAndReplaceOptions{Upsert: function.BoolPtr(true)})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "update dayChargerRule from db error:%s", dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}
	UpadteTimerChargerRuleCache(dayChargerRule)
	return nil
}

//查询所有日充电规则
func AddOneTimerChargerRule(ctx context.Context, dayChargerRule model.DayChargerRule) codes.Code {
	robotM.timerChargerLock.Lock()
	defer robotM.timerChargerLock.Unlock()
	if err := robotM.db.Collection(ctx, fmt.Sprintf("%s_index", model.DayChargerRule{}.TableName())).FindOneAndUpdate(ctx, bson.M{}, bson.M{"$inc": bson.M{"id": 1}}, &options.FindOneAndUpdateOptions{Projection: bson.M{"_id": 0}, Upsert: function.BoolPtr(true)}).Decode(&dayChargerRule); err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "insert dayChargerRule to db error,can not get index:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	_, errInsert := robotM.db.Collection(ctx, model.DayChargerRule{}.TableName()).InsertOne(ctx, dayChargerRule)
	log.Warnf("API添加一个新的定时充电规则：%+v", dayChargerRule)
	if errInsert != nil {
		log.ErrorfWithContext(ctx, "insert dayChargerRule to db error:%s", errInsert.Error())
		return codes.ErrDatabase.Wrap(errInsert)
	}
	UpadteTimerChargerRuleCache(dayChargerRule)
	return nil
}

//删除日充电规则
func DeleteOneTimerCharger(ctx context.Context, id uint16) codes.Code {
	robotM.timerChargerLock.Lock()
	defer robotM.timerChargerLock.Unlock()
	_, err := robotM.db.Collection(ctx, model.DayChargerRule{}.TableName()).DeleteOne(ctx, bson.M{"id": id})
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "delete dayChargerRule by id from db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	DeleteRuleById(id)
	return nil
}
